﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using PermissionManagement;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Volo.Abp.Authorization;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Linq;
using Volo.Abp.Security.Claims;
using Volo.Abp.Users;
using Xms.Abp.Domain.Repositories;

namespace AccountManagement;

[Dependency(ReplaceServices = true)]
public class XmsAuthorizationService : AbpAuthorizationService
{
    protected IXmsRepository<PermissionGrant, Guid> PermissionGrantRepository { get; }
    protected IAsyncQueryableExecuter AsyncExecuter { get; }
    protected ICurrentUser CurrentUser { get; }
    public XmsAuthorizationService(
        IAuthorizationPolicyProvider policyProvider,
        IAuthorizationHandlerProvider handlers,
        ILogger<DefaultAuthorizationService> logger,
        IAuthorizationHandlerContextFactory contextFactory,
        IAuthorizationEvaluator evaluator,
        IOptions<AuthorizationOptions> options,
        ICurrentPrincipalAccessor currentPrincipalAccessor,
        IAsyncQueryableExecuter asyncExecuter,
        ICurrentUser currentUser,
        IXmsRepository<PermissionGrant, Guid> permissionGrantRepository,
        IServiceProvider serviceProvider)
        : base(
            policyProvider,
            handlers,
            logger,
            contextFactory,
            evaluator,
            options,
            currentPrincipalAccessor,
            serviceProvider)
    {
        AsyncExecuter = asyncExecuter;
        CurrentUser = currentUser;
        PermissionGrantRepository = permissionGrantRepository;
    }

    public override Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements)
    {
        return base.AuthorizeAsync(user, resource, requirements);
    }

    public override async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName)
    {
        await Task.CompletedTask;
        if (CurrentUser.UserName == "admin")
        {
            return AuthorizationResult.Success();
        }
        var roleId = CurrentUser.Roles.FirstOrDefault(r => r.Length == 36);
        if (roleId.IsNullOrWhiteSpace())
        {
            return AuthorizationResult.Failed();
        }
        var index = policyName.LastIndexOf(".");
        var moduleName = policyName[..index];
        var functionName = policyName[(index + 1)..];
        var isGranted = await (await PermissionGrantRepository.AsNoTrackingAsync()).AnyAsync(r => r.ProviderName == "R" && r.ProviderKey == roleId && r.ModuleName == moduleName && r.FunctionName == functionName);

        return isGranted ? AuthorizationResult.Success() : AuthorizationResult.Failed();
    }
}
